/*
 * ModMonitorHB.c
 *
 * Created: 23/04/2012 16:00:11
 *  Author: marionse
 */ 

#include "AppDesc.h"
#include "ModMonitorHB.h"
#include "ModRF.h"
#include "ModSysTimer.h"

/** PA BO il faudrait utiliser la callback */
#include "FamGeneral.h"

/**
* \brief CONSTANTES PRIVEES DU MODULE
*/
#ifndef MOD_MONITOR_HB_TIMEOUT_US
	#define MOD_MONITOR_HB_TIMEOUT_US 45000
#endif
#ifndef MOD_MONITOR_PULSE_TIME_US
	#define MOD_MONITOR_PULSE_TIME_US 1000
#endif

/**
* \brief VARIABLES PRIVEE DU MODULE
*/
static struct  
{
	Int16U monitored_module_addr;
	TSysTime last_sys_timer_value;
	Boolean on_state; // 0:off, 1:on
	Boolean pulse_in_progress; // permet de savoir si on est en train de generer un pulse
	TSysTime last_sys_timer_for_pulse; // temps de debut du pulse
}mod_monitor_hb;

/**
* \brief FONCTION PRIVEE DU MODULE
*/
static void ModMonitorStartPulse( void );

/**
* \brief fonction d'initialisation du module
*/
ERetCode ModMonitorHBInit( void )
{
	ERetCode lo_ret_code = E_RET_SUCCESS;
	
	// au demarrage on ne connais pas le modules a surveiller
	// on va attendre le premier HB
	mod_monitor_hb.monitored_module_addr = RF_BRD_ADDR;
	ModLedSetOff( MONITOR_STATE );
	mod_monitor_hb.on_state = FALSE;
	mod_monitor_hb.pulse_in_progress = FALSE;
	
	// configure les io pour le pulse
	// LOW : entree sans pull-up
	MONITOR_PULSE_LOW_PORT &= ~MONITOR_PULSE_LOW_MASK;
	MONITOR_PULSE_LOW_DDR &= ~MONITOR_PULSE_LOW_MASK;
	
	// HIGH : sortie a 0
	MONITOR_PULSE_HIGH_PORT &= ~MONITOR_PULSE_HIGH_MASK;
	MONITOR_PULSE_HIGH_DDR |= MONITOR_PULSE_HIGH_MASK;
	
	return lo_ret_code;
}

/**
* \brief fonction appelee a chaque passage dans la boucle main
*/
ERetCode ModMonitorHBTick( void )
{
	ERetCode lo_ret_code = E_RET_SUCCESS;
	
	TRFMsg l_in_rf_msg;
	TSysTime l_sys_timer_value = SysTimerGetValue();
	
	
	// gestion du pulse
	// ATTENTION doit etre fait en premier car il est possible de demarrer un pulse avec un temps de reference deifferent
	if( TRUE == mod_monitor_hb.pulse_in_progress )
	{
		if( ((TSysTime)(l_sys_timer_value-mod_monitor_hb.last_sys_timer_for_pulse)) > MOD_MONITOR_PULSE_TIME_US )
		{
			mod_monitor_hb.pulse_in_progress = FALSE;
			
			// --__--
			MONITOR_PULSE_LOW_DDR &= ~MONITOR_PULSE_LOW_MASK;
		
			// __--__
			MONITOR_PULSE_HIGH_PORT &= ~MONITOR_PULSE_HIGH_MASK;
		}			
	}

	if( E_RET_SUCCESS == modRFGetMsg( &l_in_rf_msg ) )
	{
		// on analyse pour savoir si il s'agit d'un heartbeat
		if( E_FAM_GENERAL_ID == l_in_rf_msg.msg.family_id )
		{
			if( FAM_GEN_CMD_HB_ID == l_in_rf_msg.msg.cmd_id )
			{
				if( FAM_GEN_CMD_HB_PAYLOAD_SIZE == l_in_rf_msg.msg.len )
				{
					if( l_in_rf_msg.src_addr != mod_monitor_hb.monitored_module_addr )
					{
						// on regarde si c'est la premiere fois
						if( RF_BRD_ADDR == mod_monitor_hb.monitored_module_addr )
						{
							mod_monitor_hb.monitored_module_addr = l_in_rf_msg.src_addr;
							mod_monitor_hb.last_sys_timer_value = l_sys_timer_value;
							// on cree le pulse sur la sortie
							ModMonitorStartPulse();
							// on change l'etat
							ModLedSetOn( MONITOR_STATE );
							mod_monitor_hb.on_state = TRUE;
						}
					}
					else
					{
						// on remet le compteur a jour
						mod_monitor_hb.last_sys_timer_value = l_sys_timer_value;
						// attention si on etait eteint on doit se rallumer
						if( FALSE == mod_monitor_hb.on_state )
						{
							// on cree le pulse sur la sortie
							ModMonitorStartPulse();
							// on change l'etat
							ModLedSetOn( MONITOR_STATE );
							mod_monitor_hb.on_state = TRUE;
						}
					}					
				}
			}
		}
	}
	
	// surveillance de la perte
	// ATTENTION doit etre mis apres la gestion du pulse a cause d'une mise a jour du timer
	if( (TRUE == mod_monitor_hb.on_state) &&
		(((TSysTime)(l_sys_timer_value-mod_monitor_hb.last_sys_timer_value)) > MOD_MONITOR_HB_TIMEOUT_US) 
	  )
	{
		// on eteint
		// on cree le pulse sur la sortie
		ModMonitorStartPulse();
		// on change l'etat
		ModLedSetOff( MONITOR_STATE );
		mod_monitor_hb.on_state = FALSE;
	}
	
	return lo_ret_code;
}

/**
* \brief permet d'amorcer le pulse de commande externe
*/
static void ModMonitorStartPulse( void )
{
	if( FALSE == mod_monitor_hb.pulse_in_progress )
	{
		/** ATTENTION on risque de ne plus etre synchronise */
		// --__--
		MONITOR_PULSE_LOW_DDR |= MONITOR_PULSE_LOW_MASK;
		
		// __--__
		MONITOR_PULSE_HIGH_PORT |= MONITOR_PULSE_HIGH_MASK;
		
		mod_monitor_hb.pulse_in_progress = TRUE;
		mod_monitor_hb.last_sys_timer_for_pulse = SysTimerGetValue();
	}
}
